using System;
using System.Collections.Generic;
using System.Linq;
using AForge.Imaging;

namespace MD.ImageProcessing.Cell
{
    public class CellTracker
    {
        public List<Cell> TrackingList = new List<Cell>();

        public void AddObjectRectangles(Blob[] blobs)
        {
            foreach (var blob in blobs)
            {
                AddToTrackingCells(blob);
            }
        }

        public void AddToTrackingCells(Blob blob)
        {
            var candidateCells = new List<Cell>();
            var candidateState = new CellState(blob);

            foreach (var cell in TrackingList)
            {
                if (CellState.Compare(cell.LastState, candidateState))
                {
                    if (candidateCells.Count(c => c.Id == cell.Id) == 0)
                        candidateCells.Add(cell);
                }
            }

            //not found any cell?
            if (candidateCells.Count == 0)
            {
                //new cell
                var cell = new Cell(candidateState);
                TrackingList.Add(cell);
            }
            //found 1
            else
            {
                var isOld = ResolveCandidate(candidateCells, candidateState, 0.5);
                //New
                if (!isOld.Item1)
                {
                    TrackingList.Add(new Cell(candidateState));
                }
                //old
                else
                {
                    TrackingList.Single(k => k.Id == isOld.Item2).AddState(candidateState);
                }
            }
        }

        private Tuple<bool, int> ResolveCandidate(List<Cell> candidateRects, CellState candidateState, double d1)
        {
            if (candidateRects.Count == 0)
            {
                return Tuple.Create(false, 0);
            }
            if (candidateRects.Count == 1)
            {
                return Tuple.Create(true, candidateRects.First().Id);
            }

            var cells = candidateRects.Where(c => CellState.Compare(c.LastState, candidateState)).ToList();
            if (d1 < 0.01)
            {
                return FindNearest(cells, candidateState);
            }

            ResolveCandidate(cells, candidateState, d1 - 0.01);
            return Tuple.Create(false, 0);
        }

        private Tuple<bool, int> FindNearest(List<Cell> theSameSizes, CellState state)
        {
            double min = int.MaxValue;
            foreach (var candidateRect in theSameSizes)
            {
                var rectToCompare = candidateRect.LastState.BoundRect;
                var XX = Math.Pow((rectToCompare.X - state.BoundRect.X), 2);
                var YY = Math.Pow((rectToCompare.Y - state.BoundRect.Y), 2);
                double d = Math.Sqrt(XX + YY);
                min = min < d ? min : d;
            }
            foreach (var candidateCell in theSameSizes)
            {
                var rectToCompare = candidateCell.LastState.BoundRect;
                var XX = Math.Pow((rectToCompare.X - state.BoundRect.X), 2);
                var YY = Math.Pow((rectToCompare.Y - state.BoundRect.Y), 2);
                double d = Math.Sqrt(XX + YY);
                if (Math.Abs(d - min) < 0.001)
                {
                    if (min < 50)
                    {
                        theSameSizes.Clear();
                        theSameSizes.Add(new Cell(state));
                        return Tuple.Create(true, candidateCell.Id);
                    }
                }
            }
            theSameSizes.Clear();
            return Tuple.Create(false, 0);
        }
    }
}